msg_tool\scripts\hexen_haus\img/
png.rs1use crate::ext::io::*;
3use crate::scripts::base::*;
4use crate::types::*;
5use crate::utils::img::*;
6use anyhow::Result;
7use std::io::{Read, Seek, SeekFrom};
8
9#[derive(Debug)]
10pub struct PngImageBuilder {}
12
13impl PngImageBuilder {
14 pub fn new() -> Self {
16 PngImageBuilder {}
17 }
18}
19
20impl ScriptBuilder for PngImageBuilder {
21 fn default_encoding(&self) -> Encoding {
22 Encoding::Cp932
23 }
24
25 fn build_script(
26 &self,
27 data: Vec<u8>,
28 _filename: &str,
29 _encoding: Encoding,
30 _archive_encoding: Encoding,
31 config: &ExtraConfig,
32 _archive: Option<&Box<dyn Script>>,
33 ) -> Result<Box<dyn Script>> {
34 Ok(Box::new(PngImage::new(MemReader::new(data), config)?))
35 }
36
37 fn extensions(&self) -> &'static [&'static str] {
38 &["png"]
39 }
40
41 fn script_type(&self) -> &'static ScriptType {
42 &ScriptType::HexenHausPng
43 }
44
45 fn is_image(&self) -> bool {
46 true
47 }
48
49 fn is_this_format(&self, _filename: &str, buf: &[u8], buf_len: usize) -> Option<u8> {
50 if buf_len >= 4 && buf.starts_with(b"IMGD") {
51 return Some(10);
52 }
53 None
54 }
55}
56
57#[derive(Debug)]
58pub struct ExtraInfo {
60 pub offset_x: u32,
62 pub offset_y: u32,
64}
65
66#[derive(Debug)]
67pub struct PngImage {
68 reader: MemReader,
69 extra: Option<ExtraInfo>,
70}
71
72impl PngImage {
73 pub fn new(mut reader: MemReader, _config: &ExtraConfig) -> Result<Self> {
75 let mut header = [0; 4];
76 reader.read_exact(&mut header)?;
77 if &header != b"IMGD" {
78 return Err(anyhow::anyhow!("Not a valid HexenHaus PNG image"));
79 }
80 reader.seek(SeekFrom::End(-14))?;
81 let cnt = reader.read_exact_vec(12)?;
82 let extra = if cnt.starts_with(b"CNTR") {
83 let mut cnt_reader = MemReaderRef::new(&cnt[4..]);
84 let offset_x = cnt_reader.read_u32()?;
85 let offset_y = cnt_reader.read_u32()?;
86 Some(ExtraInfo { offset_x, offset_y })
87 } else {
88 None
89 };
90 Ok(PngImage { reader, extra })
91 }
92}
93
94impl Script for PngImage {
95 fn default_output_script_type(&self) -> OutputScriptType {
96 OutputScriptType::Json
97 }
98
99 fn default_format_type(&self) -> FormatOptions {
100 FormatOptions::None
101 }
102
103 fn is_image(&self) -> bool {
104 true
105 }
106
107 fn export_image(&self) -> Result<ImageData> {
108 let mut reader = self.reader.to_ref();
109 reader.pos = 0;
110 let reader = StreamRegion::with_start_pos(reader, 0x10)?;
111 let img = load_png(reader)?;
112 Ok(img)
113 }
114
115 fn extra_info<'a>(&'a self) -> Option<Box<dyn AnyDebug + 'a>> {
116 self.extra
117 .as_ref()
118 .map(|e| Box::new(e) as Box<dyn AnyDebug>)
119 }
120}